/**
 * @author: Miss.杨
 * @date: 2025年3月09日 09:13:42
 * @description: 
 */
package com.sheepone.monitor.server.handler.connect;

import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

import com.sheepone.webdev.log.WebDevLogger;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelId;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelHandler.Sharable;

/**
 * @author: Miss.杨
 * @date: 2025年3月09日 09:13:42
 * @description:
 */
@Sharable
public class ConnectionManager extends ChannelInboundHandlerAdapter {

    private static WebDevLogger logger = WebDevLogger.getLogger(ConnectionManager.class);

    private static final ConcurrentHashMap<ChannelId, ConnectionMeta> CONNECTIONS = new ConcurrentHashMap<>();

    public static ConnectionMeta get(ChannelId id) {
        return CONNECTIONS.get(id);
    }

    public static void register(ChannelId id, ConnectionMeta meta) {
        if (CONNECTIONS.containsKey(id)) {
            return;
        }
        CONNECTIONS.put(id, meta);
    }

    public static void remove(ChannelId id) {
        ConnectionMeta meta = CONNECTIONS.remove(id);
        if (meta != null) {
            meta.getChannel().close();
        }
    }

    public static boolean isEmpty() {
        return CONNECTIONS.isEmpty();
    }

    public static List<Channel> getUnhealthyChannels(long time, TimeUnit unit) {
        long duration = unit.toMillis(time);
        long now = System.currentTimeMillis();
        List<Channel> channels = new ArrayList<>();
        for (ConnectionMeta meta : CONNECTIONS.values()) {
            if ((!meta.getChannel().isActive()) || (now - meta.getLastHeartbeatTime() > duration)) {
                channels.add(meta.getChannel());
            }
        }
        return channels;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        register(channel.id(), new ConnectionMeta(channel));
        logger.info("Client connected from {}.",channel.remoteAddress());
        ctx.fireChannelActive();
    }

    public void channelInactive(ChannelHandlerContext ctx) {
        Channel channel = ctx.channel();
        remove(channel.id());
        logger.info("Client from {} has disconnected.",channel.remoteAddress());
        ctx.fireChannelInactive();
    }
}
